home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 37
/
Aminet 37 (2000)(Schatztruhe)[!][Jun 2000].iso
/
Aminet
/
dev
/
lang
/
sofa.lha
/
sofa
/
smalleiffel
/
lib_number
/
number.e
< prev
next >
Wrap
Text File
|
2000-03-25
|
19KB
|
918 lines
-- This file is free software, which comes along with SmallEiffel. This
-- software is distributed in the hope that it will be useful, but WITHOUT
-- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-- FITNESS FOR A PARTICULAR PURPOSE. You can modify it as you want, provided
-- this header is kept unaltered, and a notification of the changes is added.
-- You are allowed to redistribute it and sell it, alone or as a part of
-- another product.
-- Copyright (C) 1994-98 LORIA - UHP - CRIN - INRIA - FRANCE
-- Dominique COLNET and Suzanne COLLIN - colnet@loria.fr
-- http://SmallEiffel.loria.fr
--
deferred class NUMBER
--
-- This abstract definition of a NUMBER is intended to be the unique
-- view of the client (do not use sub-classes names at all in the
-- client code). In order to create NUMBERs without using concrete
-- class name, the client code can inherit NUMBER_TOOLS (see directory
-- ${SmallEiffel}/lib_show/number for example.
--
inherit
HASHABLE
undefine
is_equal
redefine
fill_tagged_out_memory, out_in_tagged_out_memory
end;
feature -- Binary operators for two NUMBERs :
infix "+" (other: NUMBER): NUMBER is
-- Sum of `Current' and `other'.
require
other /= Void
deferred
ensure
Result /= Void
end;
infix "-" (other: NUMBER): NUMBER is
-- Difference of `Current' and `other'.
require
other /= Void
do
Result := Current + (- other);
ensure
Result /= Void
end;
infix "*" (other: NUMBER): NUMBER is
-- Product of 'Current' and 'other'.
require
other /= Void
deferred
ensure
Result /= Void
end;
infix "/" (other: NUMBER): NUMBER is
-- Quotient of `Current' and `other'.
require
not (other @= 0)
divisible(other);
do
Result := Current * other.inverse;
ensure
Result /= Void
end;
infix "//" (other: NUMBER): NUMBER is
-- Divide Current by `other' (Integer division).
require
is_abstract_integer;
other.is_abstract_integer;
divisible (other);
deferred
ensure
Result.is_abstract_integer;
end;
infix "\\" (other: NUMBER): NUMBER is
-- Remainder of division of Current by `other'.
require
is_abstract_integer;
other.is_abstract_integer;
divisible (other);
deferred
ensure
Result.is_abstract_integer;
end;
infix "^" (exp: NUMBER): NUMBER is
-- 'Current' raised to 'exp'-th power.
require
exp.is_abstract_integer;
exp.is_positive;
not (is_zero and then exp.is_zero);
local
e: NUMBER;
factor: NUMBER;
do
Result := one;
factor := Current;
from
e := exp;
until
e.is_zero
loop
if (e @\\ 2) @= 1 then
Result := Result * factor;
end;
e := e @// 2;
factor := factor * factor;
end;
ensure
Result /= Void;
exp.is_zero implies Result.is_one;
end;
infix "<" (other: NUMBER): BOOLEAN is
-- Is `Current' strictly less than `other'?
require
other_exists: other /= Void;
deferred
ensure
asymmetric: Result implies not (other <= Current);
end;
infix "<=" (other: NUMBER): BOOLEAN is
-- Is `Current' less or equal than `other'?
require
other_exists: other /= Void;
do
Result := not (other < Current);
ensure
definition: Result = (Current < other) or same_as(other);
end;
infix ">" (other: NUMBER): BOOLEAN is
-- Is `Current' strictly greater than `other'?
require
other_exists: other /= Void;
do
Result := (other < Current);
ensure
definition: Result = (other < Current);
end;
infix ">=" (other: NUMBER): BOOLEAN is
-- Is `Current' greater or equal than `other'?
require
other_exists: other /= Void;
do
Result := not (Current < other);
ensure
definition: Result = (other <= Current);
end;
gcd(other: NUMBER): ABSTRACT_INTEGER is
-- Great Common Divisor of `Current' and `other'.
require
other.is_abstract_integer;
is_abstract_integer;
is_positive;
other.is_positive;
do
if other.is_zero then
Result ?= Current;
check
Result /= Void;
end;
else
Result := other.gcd(Current \\ other);
end;
end;
feature -- Unary operators for two NUMBERs :
frozen prefix "+" : NUMBER is
-- Unary plus of 'Current'.
do
Result := Current;
ensure
Result = Current
end;
prefix "-" : NUMBER is
-- Negative of 'Current'.
deferred
ensure
Result /= Void
end;
feature -- To know more about a NUMBER :
in_range(lower, upper: NUMBER): BOOLEAN is
-- Return true if `Current' is in range [`lower'..`upper']
do
Result := (Current >= lower) and then (Current <= upper);
ensure
Result = (Current >= lower and Current <= upper);
end;
compare(other: NUMBER): INTEGER is
-- Compare `Current' with `other'.
-- `<' <==> `Result < 0'
-- `>' <==> `Result > 0'
-- Otherwise `Result = 0'.
require
other /= Void;
do
if (Current < other) then
Result := -1;
elseif (other < Current) then
Result := 1;
end;
ensure
(Result < 0) = (Current < other);
(Result = 0) = not (Current < other or Current > other);
(Result > 0) = (Current > other);
end;
min(other: NUMBER): NUMBER is
-- Minimum of `Current' and `other'.
require
other /= Void;
do
if Current < other then
Result := Current;
else
Result := other;
end;
ensure
Result <= Current and then Result <= other;
compare(Result) = 0 or else other.compare(Result) = 0;
end;
max(other: NUMBER): NUMBER is
-- Maximum of `Current' and `other'.
require
other /= Void;
do
if (other < Current) then
Result := Current;
else
Result := other;
end;
ensure
(Result >= Current) and then (Result >= other);
compare(Result) = 0 or else other.compare(Result) = 0;
end;
is_zero: BOOLEAN is
-- Is it 0 ?
deferred
ensure
Result = (Current @= 0)
end;
is_one: BOOLEAN is
-- Is it 1 ?
deferred
ensure
Result = (Current @= 1)
end;
is_positive: BOOLEAN is
-- Is `Current' greater or equal zero ?
deferred
ensure
Result = (Current @>= 0)
end;
is_negative: BOOLEAN is
-- Is `Current' < 0 ?
deferred
ensure
Result = (Current @< 0)
end;
is_odd, odd: BOOLEAN is
-- Is `odd' ?
require
is_abstract_integer
do
Result := (Current @\\ 2).is_one;
end;
is_even, even: BOOLEAN is
-- Is `even' ?
require
is_abstract_integer
do
Result := (Current @\\ 2).is_zero;
end;
frozen same_as(other: NUMBER): BOOLEAN is
-- Is it the same NUMBER as `other' ?
--
-- Note: because `is_equal' uses type like Current for
-- `other', this is impossible to use directely `is_equal'.
require
other /= Void
local
x: like Current;
do
x ?= other;
Result := (x /= Void) and then x.is_equal(Current);
ensure
Result implies other.is_equal(Current)
end;
frozen is_abstract_integer: BOOLEAN is
local
abstract_integer: ABSTRACT_INTEGER;
do
abstract_integer ?= Current;
Result := abstract_integer /= Void;
end;
frozen is_abstract_fraction: BOOLEAN is
local
abstract_fraction : ABSTRACT_FRACTION;
do
abstract_fraction ?= Current;
Result := abstract_fraction /= Void;
end;
frozen is_integer: BOOLEAN is
-- Does `Current' value fit on an INTEGER ?
do
if is_abstract_integer then
if Current @<= Maximum_integer then
Result := Current @>= Minimum_integer;
end;
end;
ensure
Result implies is_abstract_integer;
end;
frozen is_double: BOOLEAN is
do
if Current #>= Minimum_double then
Result := Current #<= Maximum_double;
end;
end;
feature -- Conversions and printing :
to_integer: INTEGER is
require
is_integer
deferred
end;
to_double: DOUBLE is
require
is_double
deferred
end;
to_string: STRING is
-- Convert the NUMBER into a new allocated STRING.
-- Note: see `append_in' to save memory.
do
Result := "This is a local STRING buffer ....";
Result.clear;
append_in(Result);
Result := Result.twin;
end;
frozen digit: CHARACTER is
-- Gives the corresponding CHARACTER for range 0..9.
require
to_integer.in_range(0,9)
do
Result := to_integer.digit;
ensure
("0123456789").has(Result);
Current @= Result.value;
end;
append_in(str: STRING) is
-- Append the equivalent of `to_string' at the end of
-- `str'. Thus you can save memory because no other
-- STRING is allocate for the job.
require
str /= Void;
deferred
end;
feature -- To mimic NUMERIC :
divisible(other: NUMBER): BOOLEAN is
-- Is `other' a valid divisor for `Current' ?
require
other /= Void
do
Result := not other.is_zero;
end;
one: NUMBER is
-- The neutral element of multiplication.
once
!SMALL_INTEGER!Result.make(1);
ensure
neutral_element: -- Result is the neutral element of
-- multiplication.
end;
zero: NUMBER is
-- The neutral element of addition.
once
!SMALL_INTEGER!Result.make(0);
ensure
neutral_element: -- Result is the neutral element of
-- addition.
end;
frozen sign: INTEGER is
do
if is_positive then
Result := 1;
elseif is_negative then
Result := - 1;
end;
end;
sqrt: DOUBLE is
-- Compute the square routine.
require
is_double
do
Result := to_double.sqrt;
end;
frozen log: DOUBLE is
require
is_double
do
Result := to_double.log;
end;
abs: NUMBER is
do
if is_negative then
Result := -Current;
else
Result := Current;
end;
end;
feature -- To mix NUMBER and INTEGER :
infix "@+" (other: INTEGER): NUMBER is
-- Sum of `Current' and `other'.
deferred
ensure
Result /= Void
end;
infix "@-" (other: INTEGER): NUMBER is
-- Difference of `Current' and `other'.
local
num: ABSTRACT_INTEGER;
do
if other = Minimum_integer then
!LARGE_POSITIVE_INTEGER!num.make_smaller(0);
Result := Current + num;
else
Result := Current @+ (- other);
end;
ensure
Result /= Void
end;
infix "@*" (other: INTEGER): NUMBER is
require
other /= Void
deferred
ensure
Result /= Void
end;
infix "@/" (other: INTEGER): NUMBER is
-- Quotient of `Current` and `other`.
require
other /= 0;
deferred
ensure
Result /= Void
end;
infix "@//" (other: INTEGER): NUMBER is
-- Divide Current by `other' (Integer division).
require
is_abstract_integer;
other /= 0;
deferred
ensure
Result.is_abstract_integer;
end;
infix "@\\" (other: INTEGER): NUMBER is
-- Remainder of division of Current by `other'.
require
is_abstract_integer;
other /= 0;
deferred
ensure
Result.is_abstract_integer;
end;
infix "@^" (exp: INTEGER): NUMBER is
require
(exp > 0) or else not is_zero
local
int : INTEGER;
other : NUMBER;
do
int := exp.abs;
inspect int
when 0 then
!SMALL_INTEGER!Result.make(1);
when 1 then
Result := Current;
else
from
int := int - 1;
other := Current;
Result := Current;
until
int < 2
loop
if int.odd then
Result := Result * other;
end;
other := other * other; -- methode sqrt : ^2
int := int // 2;
end;
Result := Result * other;
end;
if (exp < 0) then
Result := Result.inverse;
end;
ensure
Result /= Void;
Result /= Current implies (exp /= 1 or else not is_zero);
end;
infix "@=" (other: INTEGER): BOOLEAN is
-- Is Current equal `other' ?
deferred
end;
infix "@<" (other: INTEGER): BOOLEAN is
-- Is 'Current' strictly less than 'other'?
deferred
ensure
Result = not (Current @>= other);
end;
infix "@<=" (other: INTEGER): BOOLEAN is
-- Is 'Current' less or equal 'other'?
deferred
ensure
Result = not (Current @> other);
end;
infix "@>" (other: INTEGER): BOOLEAN is
-- Is 'Current' strictly greater than 'other'?
deferred
ensure
Result = not (Current @<= other);
end;
infix "@>=" (other: INTEGER): BOOLEAN is
-- Is 'Current' greater or equal than 'other'?
deferred
ensure
Result = not (Current @< other);
end;
feature -- To mix NUMBER and DOUBLE :
infix "#=" (other: DOUBLE): BOOLEAN is
-- Is Current equal `other` ?
deferred
end;
infix "#<" (other: DOUBLE): BOOLEAN is
-- Is 'Current' strictly less than 'other'?
deferred
ensure
Result implies not (Current #>= other);
end;
infix "#<=" (other: DOUBLE): BOOLEAN is
-- Is `Current` less or equal `other`?
deferred
ensure
Result = not (Current #> other);
end;
infix "#>" (other: DOUBLE): BOOLEAN is
-- Is 'Current' strictly greater than 'other'?
deferred
ensure
Result = not (Current #<= other);
end;
infix "#>=" (other: DOUBLE): BOOLEAN is
-- Is `Current` greater or equal than `other`?
deferred
ensure
Result = not (Current #< other);
end;
feature -- Misc :
out_in_tagged_out_memory, fill_tagged_out_memory is
do
append_in(tagged_out_memory);
end;
hash_code: INTEGER is
do
if is_double then
Result := to_double.hash_code;
else
not_yet_implemented;
end;
end;
inverse: NUMBER is
require
divisible(Current)
deferred
ensure
Result /= Void
end;
factorial: NUMBER is
require
is_abstract_integer;
is_positive
local
n: NUMBER;
do
if is_zero then
!SMALL_INTEGER!Result.make(1);
else
from
Result := Current;
n := Current @- 1;
until
n @= 0
loop
Result := n * Result;
n := n @- 1;
end;
end;
ensure
Result.is_abstract_integer;
Result.is_positive
end;
feature {NUMBER} -- Implementation :
frozen add_with_small_integer(other: SMALL_INTEGER): NUMBER is
require
other /= Void
do
Result := Current @+ other.to_integer;
ensure
Result /= Void
end;
add_with_large_positive_integer(other: LARGE_POSITIVE_INTEGER): NUMBER is
require
other /= Void
deferred
ensure
Result /= Void
end;
add_with_large_negative_integer(other: LARGE_NEGATIVE_INTEGER): NUMBER is
require
other /= Void
deferred
ensure
Result /= Void
end;
add_with_small_fraction(other: SMALL_FRACTION): NUMBER is
require
other /= Void
deferred
ensure
Result /= Void
end;
add_with_large_fraction(other: LARGE_FRACTION): NUMBER is
require
other /= Void
deferred
ensure
Result /= Void
end;
multiply_with_small_integer(other: SMALL_INTEGER): NUMBER is
require
other /= Void
do
Result := Current @* other.to_integer;
ensure
Result /= Void
end;
multiply_with_large_positive_integer(other: LARGE_POSITIVE_INTEGER): NUMBER is
require
other /= Void
deferred
ensure
Result /= Void
end;
multiply_with_large_negative_integer(other: LARGE_NEGATIVE_INTEGER): NUMBER is
require
other /= Void
deferred
ensure
Result /= Void
end;
multiply_with_small_fraction(other: SMALL_FRACTION): NUMBER is
require
other /= Void
deferred
ensure
Result /= Void
end;
multiply_with_large_fraction(other: LARGE_FRACTION): NUMBER is
require
other /= Void
deferred
ensure
Result /= Void
end;
greater_with_small_integer(other: SMALL_INTEGER): BOOLEAN is
require
other /= Void;
do
Result := Current @> other.to_integer;
end;
greater_with_large_positive_integer(other: LARGE_POSITIVE_INTEGER): BOOLEAN is
require
other /= Void;
deferred
end;
greater_with_large_negative_integer(other: LARGE_NEGATIVE_INTEGER): BOOLEAN is
require
other /= Void;
deferred
end;
greater_with_small_fraction(other: SMALL_FRACTION): BOOLEAN is
require
other /= Void;
deferred
end;
greater_with_large_fraction(other: LARGE_FRACTION): BOOLEAN is
require
other /= Void;
deferred
end;
to_string_format(s: INTEGER): STRING is
-- Same as `to_string' but the result is on `s' character and the
-- number is right aligned.
-- Note: see `append_in_format' to save memory.
require
to_string.count <= s;
do
from
tmp_string.clear;
append_in(tmp_string);
until
tmp_string.count >= s
loop
tmp_string.add_first(' ');
end;
Result := tmp_string.twin;
ensure
Result.count = s;
end;
append_in_format(str: STRING; s: INTEGER) is
-- Append the equivalent of `to_string_format' at the end of
-- `str'. Thus you can save memory because no other
-- STRING is allocate for the job.
do
from
tmp_string.clear;
append_in(tmp_string);
until
tmp_string.count >= s
loop
tmp_string.add_first(' ');
end;
str.append(tmp_string);
ensure
str.count >= (old str.count) + s;
end;
feature {NONE}
max_double: NUMBER is
local
nt: NUMBER_TOOLS;
once
!!nt;
Result := nt.from_string(Maximum_double.to_string);
end;
min_double: NUMBER is
once
Result := -max_double @- 1;
end;
greater_large_negative_integer: LARGE_NEGATIVE_INTEGER is
once
!LARGE_NEGATIVE_INTEGER!Result.make_smaller(0);
end;
Base: INTEGER is
once
Result := Minimum_integer;
end;
Half_base: INTEGER is
once
from
Result := 1;
until
((Result.to_double * 2)^2) > Double_base
loop
Result := Result * 2;
end;
end;
Double_base: DOUBLE is
once
Result := Maximum_integer.to_double + 1;
end
smaller_correct_fixed: FIXED_ARRAY[INTEGER] is
once
!!Result.make(2);
Result.put(1,1);
end;
tmp_string: STRING is
once
!!Result.make(128);
end;
temp_2_digints: FIXED_ARRAY[INTEGER] is
once
!!Result.make(2);
end;
temp_1_digint: FIXED_ARRAY[INTEGER] is
once
!!Result.make(1);
end;
temp: FIXED_ARRAY[INTEGER] is
once
!!Result.make(3);
end;
temp_from_mult: FIXED_ARRAY[INTEGER] is
once
!!Result.make(0);
end;
temp_quotient: FIXED_ARRAY[INTEGER] is
once
!!Result.make(0);
end;
temp_remainder: FIXED_ARRAY[INTEGER] is
once
!!Result.make(0);
end;
temp_division: FIXED_ARRAY[INTEGER] is
once
!!Result.make(0);
end;
end -- NUMBER